#include "HashTable.h"
#include <stdlib.h>

void initHashTable(HashTable &hashtable, int key_byte_len, int element_bye_len){
	hashtable.count = 0;
	hashtable.key_byte_len = key_byte_len;
	hashtable.element_byte_len = element_bye_len;
	hashtable.list = (LinkNode**)malloc(sizeof(LinkNode *) * (2^(key_byte_len * 8)));
	hashtable.hashcode_fun = hashcode;
	hashtable.match_fun = equal;
	for(int i = 0; i < (2^(key_byte_len * 8)); i++){
		hashtable.list[i] = NULL;
	}
}

void initHashTable(HashTable &hashtable, int key_byte_len, int element_bye_len, 
				   code_t (*hashcode_fun)(void* q, int key_byte_len),
				   bool (*equal_fun)(void* e1_q, void* e2_q, int key_byte_len, int element_byte_len)){
	hashtable.count = 0;
	hashtable.key_byte_len = key_byte_len;
	hashtable.element_byte_len = element_bye_len;
	hashtable.list = (LinkNode**)malloc(sizeof(LinkNode *) * (2^(key_byte_len * 8)));
	hashtable.hashcode_fun = hashcode_fun;
	hashtable.match_fun = equal_fun;
	for(int i = 0; i < (2^(key_byte_len * 8)); i++){
		hashtable.list[i] = NULL;
	}
}

void freeHashTable(HashTable &hashtable){
	LinkNode *q, *tmp;
	for(int i = 0; i < (2^(hashtable.key_byte_len * 8)); i++){
		if(hashtable.list[i] != NULL){
			q = hashtable.list[i];
			while(q != NULL){
				tmp = q;
				q = q->next;
				free(tmp);
			}
		}
	}
	hashtable.key_byte_len = 0;
	hashtable.element_byte_len = 0;
	hashtable.count = 0;
	free(hashtable.list);
	hashtable.list = NULL;
}

void putHashTable(HashTable &hashtable, void* element_q){
	LinkNode* newLinkNode = (LinkNode*)malloc(sizeof(LinkNode));
	newLinkNode->element_q = element_q;
	newLinkNode->next = NULL;

	LinkNode *q = hashtable.list[(*hashtable.hashcode_fun)(element_q, hashtable.key_byte_len)];
	while(q != NULL){
		q = q->next;
	}
	q = newLinkNode;
	hashtable.count++;
}
void* findHashTable(HashTable &hashtable, void* element_q){

	LinkNode *q = hashtable.list[(*hashtable.hashcode_fun)(element_q, hashtable.key_byte_len)];

	while(q != NULL){
		if((*hashtable.match_fun)(q->element_q, element_q, hashtable.key_byte_len, hashtable.element_byte_len)) break;
		q = q->next;
	}
	return q;
}
bool equal(void* e1_q, void* e2_q, int key_byte_len, int element_byte_len){
	int i;
	byte_t* b1_q = (byte_t*)e1_q + key_byte_len;
	byte_t* b2_q = (byte_t*)e2_q + key_byte_len;
	for(i = key_byte_len; i < element_byte_len; i++){
		if(&b1_q != &b2_q) break;
	}
	if(i < element_byte_len) return false;
	else return true;
}

code_t hashcode(void* q, int key_byte_len){
	byte_t* qByte = (byte_t*)q;
	code_t code = 0;
	for(int i = 1; i <= key_byte_len; i++){
		code = code * (2^8) + (*(qByte++));
	}
	return code;
}


